package sunyu.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
import sunyu.config.Constant;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * service方法切面拦截，使其支持cache
 * <p>
 * execution(* sunyu.service.impl..*.*(..))
 * execution(): 表达式主体
 * 第一个*号：表示返回类型，*号表示所有的类型
 * 包名：表示需要拦截的包名，后面的两个句点表示当前包和当前包的所有子包
 * 第二个*号：表示类名，*号表示所有的类
 * *(..):最后这个星号表示方法名，*号表示所有的方法，后面括弧里面表示方法的参数，两个句点表示任何参数
 *
 * @author 孙宇
 */
@Aspect
@Component
public class ServiceCacheAop {

    @Resource(name = "cacheManager")
    CacheManager cacheManager;

    /**
     * 拦截所有select开头的方法，从缓存获取数据
     *
     * @param proceedingJoinPoint
     * @return
     */
    @Around("(execution(* sunyu.service.impl..*.select*(..)))")
    public Object selectMethod(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try {
            Signature signature = proceedingJoinPoint.getSignature();
            MethodSignature methodSignature = null;
            if (!(signature instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            methodSignature = (MethodSignature) signature;
            Object target = proceedingJoinPoint.getTarget();
            Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            //System.out.println("方法名:" + currentMethod.getName());

            Cache cache = cacheManager.getCache(Constant.myCacheKey);
            String key = Constant.myCacheKeyPre + currentMethod.toString();
            Object[] args = proceedingJoinPoint.getArgs();
            for (Object o : args) {
                if (o != null) {
                    key += o.toString();
                }
            }
            Cache.ValueWrapper valueWrapper = cache.get(key);
            if (valueWrapper != null) {
                result = valueWrapper.get();
            } else {
                result = proceedingJoinPoint.proceed();
                cache.put(key, result);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 拦截所有insert/update/delete开头的方法，清除缓存
     *
     * @param proceedingJoinPoint
     * @return
     */
    @Around("(execution(* sunyu.service.impl..*.insert*(..))) || (execution(* sunyu.service.impl..*.update*(..))) || (execution(* sunyu.service.impl..*.delete*(..)))")
    public Object otherMethod(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try {
            Signature signature = proceedingJoinPoint.getSignature();
            MethodSignature methodSignature = null;
            if (!(signature instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            methodSignature = (MethodSignature) signature;
            Object target = proceedingJoinPoint.getTarget();
            Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            //System.out.println("方法名:" + currentMethod.getName());

            Cache cache = cacheManager.getCache(Constant.myCacheKey);
            cache.clear();

            result = proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }

}
